package com.pokermind.dse.tcp.util;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pokermind.dse.tcp.protocol.ProtocolConstants;
import com.pokermind.dse.tcp.protocol.ProtocolMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 响应包装工具类
 * 为TCP协议提供统一的响应包装，支持requestId精确匹配
 * 
 * 功能特性:
 * 1. 自动提取客户端requestId并返回
 * 2. 统一的成功/错误响应格式
 * 3. 完整的JSON序列化处理
 * 4. 详细的错误日志记录
 * 
 * 响应格式:
 * {
 *   "rqid": 12345,           // 客户端请求ID
 *   "code": 0,               // 响应码（整数）
 *   "desc": "success",       // 响应描述
 *   "data": { ... }          // 业务数据
 * }
 * 
 * @author PokerMind Team
 */
public class ResponseWrapper {
    
    private static final Logger logger = LoggerFactory.getLogger(ResponseWrapper.class);
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 创建成功响应
     * 
     * @param request 原始请求消息
     * @param desc 成功描述
     * @param data 响应数据
     * @return 包装后的协议响应消息
     */
    public static ProtocolMessage createSuccessResponse(ProtocolMessage request, String desc, Object data) {
        return createResponse(request, 200, desc, data);
    }
    
    /**
     * 创建错误响应
     * 
     * @param request 原始请求消息
     * @param code 错误码（整数）
     * @param desc 错误描述
     * @return 包装后的协议响应消息
     */
    public static ProtocolMessage createErrorResponse(ProtocolMessage request, int code, String desc) {
        return createResponse(request, code, desc, null);
    }
    
    /**
     * 创建业务错误响应
     * 
     * @param request 原始请求消息
     * @param desc 错误描述
     * @param detail 详细错误信息
     * @return 包装后的协议响应消息
     */
    public static ProtocolMessage createBusinessErrorResponse(ProtocolMessage request, String desc, String detail) {
        Map<String, Object> errorData = new LinkedHashMap<>();
        errorData.put("error", desc);
        errorData.put("detail", detail);
        return createResponse(request, 4000, desc, errorData);
    }
    
    /**
     * 创建通用响应
     * 
     * @param request 原始请求消息
     * @param code 响应码（整数）
     * @param desc 响应描述
     * @param data 响应数据
     * @return 包装后的协议响应消息
     */
    public static ProtocolMessage createResponse(ProtocolMessage request, int code, String desc, Object data) {
        try {
            // 提取客户端请求ID
            String clientRequestId = extractClientRequestId(request);
            if (clientRequestId == null) {
                clientRequestId = java.util.UUID.randomUUID().toString().replace("-", ""); // 兜底生成UUID
            }
            
            // 构造标准响应格式
            Map<String, Object> responseWrapper = new LinkedHashMap<>();
            responseWrapper.put("rqid", clientRequestId);  // 改为 rqid（UUID格式）
            responseWrapper.put("code", code);             // 整数类型
            responseWrapper.put("desc", desc);             // 改为 desc
            // V4.31: data为null时不返回，保持响应简洁
            if (data != null) {
                responseWrapper.put("data", data);
            }
            
            // 序列化响应
            String responseJson = objectMapper.writeValueAsString(responseWrapper);
            
            // 创建响应消息
            ProtocolMessage response = ProtocolMessage.createResponse(request, responseJson);
            
            if (logger.isDebugEnabled()) {
                logger.debug("Created response: rqid={}, protocol={}, code={}, desc={}", 
                    clientRequestId, response.getProtocolName(), code, desc);
            }
            
            return response;
            
        } catch (Exception e) {
            logger.error("Failed to create wrapped response: request={}, code={}, desc={}, error={}", 
                request.getProtocolName(), code, desc, e.getMessage());
                
            // 创建简单的错误响应作为兜底
            return ProtocolMessage.createErrorResponse(request, 500, "Internal server error: " + e.getMessage());
        }
    }
    
    /**
     * 从请求中提取客户端请求ID
     * 
     * @param request 原始请求消息
     * @return 客户端请求ID，如果不存在则返回null
     */
    public static String extractClientRequestId(ProtocolMessage request) {
        try {
            JsonNode jsonNode = request.getJsonNode();
            if (jsonNode != null && jsonNode.has("rqid")) {
                return jsonNode.get("rqid").asText();
            }
            
            // 如果JsonNode为空，尝试解析JSON字符串
            if (jsonNode == null && request.getJsonBody() != null) {
                JsonNode parsedNode = objectMapper.readTree(request.getJsonBody());
                if (parsedNode.has("rqid")) {
                    return parsedNode.get("rqid").asText();
                }
            }
            
            logger.warn("No rqid found in request: protocol={}, body={}", 
                request.getProtocolName(), 
                request.getJsonBody().length() > 100 ? request.getJsonBody().substring(0, 100) + "..." : request.getJsonBody());
            return null;
            
        } catch (Exception e) {
            logger.error("Failed to extract clientRequestId from request {}: {}", 
                request.getProtocolName(), e.getMessage());
            return null;
        }
    }
    
    /**
     * 从请求中提取业务数据
     * 期望JSON格式: {"requestId": 123, "data": {...}}
     * 
     * @param request 原始请求消息
     * @param targetClass 目标业务对象类型
     * @return 解析后的业务对象
     * @throws Exception 解析失败或格式不正确时抛出异常
     */
    public static <T> T extractBusinessData(ProtocolMessage request, Class<T> targetClass) throws Exception {
        JsonNode jsonNode = request.getJsonNode();
        if (jsonNode == null) {
            jsonNode = objectMapper.readTree(request.getJsonBody());
        }
        
        // 新格式必须包含data字段
        if (!jsonNode.has("data")) {
            throw new IllegalArgumentException("Request missing 'data' field: protocol=" + request.getProtocolName());
        }
        
        JsonNode dataNode = jsonNode.get("data");
        if (dataNode == null || dataNode.isNull()) {
            throw new IllegalArgumentException("Request 'data' field is null: protocol=" + request.getProtocolName());
        }
        
        return objectMapper.treeToValue(dataNode, targetClass);
    }
    
}
